<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=0,minimum-scale=1.0,maximum-scale=1.0" />
    <meta name="author" content="火星科技 http://mars3d.cn " />
    <meta name="apple-touch-fullscreen" content="yes" />
    <meta name="apple-mobile-web-app-capable" content="yes" />
    <meta name="apple-mobile-web-app-status-bar-style" content="black" />
    <meta name="format-detection" content="telephone=no" />
    <meta name="x5-fullscreen" content="true" />
    <meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1" />
    <!-- 标题及搜索关键字 -->
    <meta name="keywords" content="火星科技,cesium,3D,GIS,marsgis,三维,地球,地图,开发,框架,系统,示例,资料,模型,离线,外包,合肥,安徽,中国" />
    <meta
      name="description"
      content="火星科技 合肥火星 合肥火星科技 合肥火星科技有限公司 leaflet leaflet框架 leaflet开发 cesium cesium开发 cesium框架 三维 地球 模型  gis marsgis 地图离线 地图开发 地图框架 地图外包 框架 开发 外包  地图离线 二维地图 三维地图 全景漫游 地理信息系统 云GIS 三维GIS GIS平台 WebGIS"
    />

    <link rel="shortcut icon" type="image/x-icon" href="http://mars3d.cn/favicon.ico" />
    <title>三维地图 | Mars3D | 三维地图 | 火星科技 | 合肥火星科技有限公司</title>

    <!--第三方lib-->
    <script
      type="text/javascript"
      src="../lib/include-lib.js"
      libpath="../lib/"
      include="jquery,font-awesome,echarts,bootstrap,layer,haoutil,turf,mars3d"
    ></script>

    <link href="css/style.css" rel="stylesheet" />
  </head>

  <body class="dark">
    <!--加载前进行操作提示，优化用户体验-->
    <div id="mask" class="signmask" onclick="removeMask()"></div>

    <div id="mars3dContainer" class="mars3d-container"></div>

    <div class="infoview">
      <div id="section" style="width: 400px; height: 250px"></div>
    </div>

    <script src="./js/common.js"></script>
    <script type="text/javascript">
      'use script' //开发环境建议开启严格模式

      var map
      var graphicLayer

      //时间控制参数
      var args = {
        space: 100,
        time: 5,
        martTimeInter: null,
        cleanTimeInter: null,
      }

      function initMap(options) {
        //合并属性参数，可覆盖config.json中的对应配置
        var mapOptions = mars3d.Util.merge(options, {
          scene: {
            center: {
              y: 31.799613,
              x: 117.27357,
              z: 72.55,
              heading: 59.8,
              pitch: -18,
              roll: 0,
            },
          },
          control: {
            animation: true, //是否创建动画小器件，左下角仪表
            timeline: true, //是否显示时间线控件
          },
        })

        //创建三维地球场景
        map = new mars3d.Map('mars3dContainer', mapOptions)

        //创建Graphic图层
        graphicLayer = new mars3d.layer.GraphicLayer()
        map.addLayer(graphicLayer)

        //合肥高铁
        var coors = [
          [117.277697, 31.800233, 45],
          [117.262022, 31.798983, 45],
          [117.229506, 31.793351, 45],
          [117.215719, 31.791085, 45],
          [117.207234, 31.79079, 45],
          [117.180246, 31.790688, 45],
          [117.168311, 31.789785, 45],
          [117.152322, 31.789855, 45],
          [117.125297, 31.788849, 45],
          [117.091144, 31.787516, 45],
        ]

        var positions = mars3d.PointTrans.lonlats2cartesians(coors)

        //插值求新路线（按固定间隔米数插值）
        var positionsNew = mars3d.PolyUtil.interLine(positions, {
          minDistance: 20, //间隔20米
        })

        //求对比的贴地地面高度（用于echarts展示）
        mars3d.PolyUtil.computeSurfacePoints({
          scene: map.scene,
          positions: positionsNew, //需要计算的源路线坐标数组
          callback: function (raisedPositions, noHeight) {
            //raisedPositions为含高程信息的新坐标数组，noHeight为标识是否存在无地形数据。
            console.log(raisedPositions)

            inintRoad(positionsNew, raisedPositions)
          },
        })
      }

      //构造动态高铁   positions:设计的路线    positionsTD地面的贴地路线（用于比较）
      function inintRoad(positionsSJ, positionsTD) {
        var heightArray = []
        var heightTDArray = []
        var mpoints = []
        for (let i = 0; i < positionsSJ.length; i++) {
          let position = positionsSJ[i]
          let carto = Cesium.Cartographic.fromCartesian(position)
          let x = Cesium.Math.toDegrees(carto.longitude)
          let y = Cesium.Math.toDegrees(carto.latitude)

          let height = mars3d.Util.formatNum(carto.height) //设计高度
          let tdHeight = mars3d.Util.formatNum(Cesium.Cartographic.fromCartesian(positionsTD[i]).height) //地面高度

          heightArray.push(height)
          heightTDArray.push(tdHeight)
          mpoints.push([x, y, height, tdHeight])
        }

        // 距离数组
        var positionsLineFirst = positionsTD[0]
        var distanceArray = positionsTD.map(function (data) {
          return Math.round(Cesium.Cartesian3.distance(data, positionsLineFirst))
        })

        //显示echarts
        drawHeightToDistanceEcharts(heightArray, heightTDArray, distanceArray)

        // 画线
        var primitive = new mars3d.graphic.PolylinePrimitive({
          id: '设计路线',
          positions: positionsSJ,
          style: {
            width: 3,
            color: Cesium.Color.RED,
            materialType: mars3d.MaterialType.PolylineDash, //虚线
            dashLength: 20,
          },
        })
        graphicLayer.addGraphic(primitive)

        var primitiveTD = new mars3d.graphic.PolylinePrimitive({
          id: '贴地路线',
          positions: positionsTD,
          style: {
            width: 3,
            color: Cesium.Color.YELLOW,
          },
        })
        graphicLayer.addGraphic(primitiveTD)

        //=================计算路线====================
        var start = map.clock.currentTime.clone()

        var counts = mpoints.length

        var arrProperty = []
        var arrTime = []

        //16组车身+头尾2个车头 共18组
        for (let j = 0; j < 18; j++) {
          let stime = Cesium.JulianDate.addSeconds(start, j, new Cesium.JulianDate())
          arrTime.push(stime)

          let property = new Cesium.SampledPositionProperty()

          for (let i = 0; i < counts; i++) {
            let time = Cesium.JulianDate.addSeconds(stime, i + 1, new Cesium.JulianDate())
            let point = Cesium.Cartesian3.fromDegrees(mpoints[i][0], mpoints[i][1], mpoints[i][2] + 0.5)
            property.addSample(time, point)
          }

          property.setInterpolationOptions({
            interpolationDegree: 1,
            interpolationAlgorithm: Cesium.LinearApproximation,
          })
          arrProperty.push(property)
        }

        //=================时间相关====================

        let stop = Cesium.JulianDate.addSeconds(start, mpoints.length + 60, new Cesium.JulianDate())
        map.clock.startTime = start.clone()
        map.clock.stopTime = stop.clone()
        map.clock.currentTime = start.clone()
        map.clock.multiplier = 1
        map.clock.shouldAnimate = true
        // map.clock.clockRange = Cesium.ClockRange.LOOP_STOP; //到达终止时间后循环

        if (map.viewer.timeline) {
          map.viewer.timeline.zoomTo(start, stop)
        }

        let availability = new Cesium.TimeIntervalCollection([
          new Cesium.TimeInterval({
            start: start,
            stop: Cesium.JulianDate.addSeconds(start, counts, new Cesium.JulianDate()),
          }),
        ])

        //=================添加高铁车头================
        let graphicHead = addTrainHead(arrProperty[0], availability)
        map.trackedEntity = graphicHead.entity

        //=================添加车身====================
        let len = arrProperty.length
        for (let j = 1; j < len - 1; j++) {
          addTrainBody(arrProperty[j], availability)
        }

        //车尾部的反向车头
        addTrainHead(arrProperty[len - 1], availability, true)

        //==============添加铁路，定时更新================
        addRailway(graphicHead, mpoints)

        //==============更新echarts================
        let lastDistance

        function locTrain() {
          let t = parseInt(map.clock.currentTime.secondsOfDay - map.clock.startTime.secondsOfDay)
          if (t >= heightArray.length) {
            clearInterval(args.martTimeInter)
            clearInterval(args.cleanTimeInter)
            return
          }
          if (lastDistance == t) {
            return
          }
          lastDistance = t
          updateEchartsDistance(t, heightArray[t])
        }
        args.martTimeInter = setInterval(locTrain, 100)
      }

      //添加车头
      function addTrainHead(position, availability, rotatePI) {
        var graphicModel = new mars3d.graphic.ModelEntity({
          name: '和谐号车头',
          position: position,
          orientation: new Cesium.VelocityOrientationProperty(position),
          availability: availability,
          style: {
            url: '//data.mars3d.cn/gltf/mars/train/heada.glb',
            scale: 0.001,
            minimumPixelSize: 16,
            heading: rotatePI ? 90 : -90,
          },
        })
        graphicLayer.addGraphic(graphicModel)
        return graphicModel
      }

      //添加车身
      function addTrainBody(position, availability) {
        var graphicModel = new mars3d.graphic.ModelEntity({
          name: '和谐号车身',
          position: position,
          orientation: new Cesium.VelocityOrientationProperty(position),
          availability: availability,
          style: {
            url: '//data.mars3d.cn/gltf/mars/train/body.glb',
            scale: 0.001,
            minimumPixelSize: 16,
            heading: -90,
          },
        })
        graphicLayer.addGraphic(graphicModel)
        return graphicModel
      }

      //添加铁路，定时更新
      function addRailway(graphicHead, mpoints) {
        let positions = []
        let orientations = []

        let times = graphicHead.position._property._times
        let start = times[0].clone()
        let counts = times.length

        let position
        let orientation
        for (let k = 1; k < counts; k++) {
          let time = times[k]

          position = graphicHead.position.getValue(time)
          positions.push(position)

          orientation = graphicHead.orientation.getValue(time)
          orientations.push(orientation)
        }

        let i = 0
        let roadNum = 80

        function addroad() {
          let space = Math.round(map.clock.currentTime.secondsOfDay - map.clock.startTime.secondsOfDay)
          let spa = space + args.space
          if (spa > counts) {
            spa = counts
          }
          for (; i < spa; i++) {
            let availability = new Cesium.TimeIntervalCollection([
              new Cesium.TimeInterval({
                start: Cesium.JulianDate.addSeconds(start, -roadNum + i, new Cesium.JulianDate()),
                stop: Cesium.JulianDate.addSeconds(start, roadNum + i, new Cesium.JulianDate()),
              }),
            ])

            if (mpoints[i][2] - mpoints[i][3] < -20 || (i > 2 && mpoints[i - 3][2] - mpoints[i - 3][3] < -20)) {
              let id = 's' + i
              let graphic = graphicLayer.getGraphicById(id)
              if (!graphic) {
                let graphicModel = new mars3d.graphic.ModelEntity({
                  id: id,
                  position: positions[i],
                  orientation: orientations[i],
                  availability: availability,
                  style: {
                    url: '//data.mars3d.cn/gltf/mars/railway/suidao.glb',
                    scale: 0.001,
                  },
                })
                graphicLayer.addGraphic(graphicModel)
              } else {
                graphic.entity.availability._intervals[0].stop.secondsOfDay = availability._intervals[0].stop.secondsOfDay
              }
            }

            let id = 'xl' + i
            let graphic = graphicLayer.getGraphicById(id)
            if (!graphic) {
              let graphicModel = new mars3d.graphic.ModelEntity({
                id: id,
                position: positions[i],
                orientation: orientations[i],
                availability: availability,
                style: {
                  url: '//data.mars3d.cn/gltf/mars/railway/railway.glb',
                  scale: 0.001,
                },
              })
              graphicLayer.addGraphic(graphicModel)
            } else {
              graphic.entity.availability._intervals[0].stop.secondsOfDay = availability._intervals[0].stop.secondsOfDay
            }

            if (mpoints[i][2] - mpoints[i][3] > 20 && i % 5 == 0) {
              let id = 'xq' + i
              let graphic = graphicLayer.getGraphicById(id)
              if (!graphic) {
                let graphicModel = new mars3d.graphic.ModelEntity({
                  id: id,
                  position: positions[i],
                  orientation: orientations[i],
                  availability: availability,
                  style: {
                    url: '//data.mars3d.cn/gltf/mars/railway/bridge.glb',
                    scale: 0.001,
                  },
                })
                graphicLayer.addGraphic(graphicModel)
              } else {
                graphic.entity.availability._intervals[0].stop.secondsOfDay = availability._intervals[0].stop.secondsOfDay
              }
            }

            if (i % 12 == 0) {
              let id = 'xd' + i
              let graphic = graphicLayer.getGraphicById(id)
              if (!graphic) {
                let graphicModel = new mars3d.graphic.ModelEntity({
                  id: id,
                  position: positions[i],
                  orientation: orientations[i],
                  availability: availability,
                  style: {
                    url: '//data.mars3d.cn/gltf/mars/railway/jiazi.glb',
                    scale: 0.001,
                  },
                })
                graphicLayer.addGraphic(graphicModel)
              } else {
                graphic.entity.availability._intervals[0].stop.secondsOfDay = availability._intervals[0].stop.secondsOfDay
              }
            }
          }

          //移除铁路
          for (let j = args.statate; j < args.statate - args.space; j++) {
            removeGraphic('s' + j)
            removeGraphic('xl' + j)
            removeGraphic('xq' + j)
            removeGraphic('xd' + j)
            args.statate = j
          }
        }

        addroad()

        args.cleanTimeInter = setInterval(addroad, args.time)
        args.statate = 0
      }

      function removeGraphic(id) {
        let graphic = graphicLayer.getGraphicById(id)
        if (graphic) {
          if (graphic.entity.availability._intervals[0].stop.secondsOfDay < map.clock.currentTime.secondsOfDay) {
            graphic.remove(true)
          }
        }
      }

      //图表
      var myChart

      //生成echarts图表
      function drawHeightToDistanceEcharts(heightArray, heightTDArray, distanceArray) {
        if (myChart == null) {
          myChart = echarts.init(document.getElementById('section'), 'dark')
        }

        var option = {
          title: {
            text: '断面图',
          },
          tooltip: {
            trigger: 'axis',
            axisPointer: {
              type: 'cross',
            },
          },
          toolbox: {
            show: false,
            feature: {
              saveAsImage: {},
            },
          },
          legend: {
            data: ['地形高程', '设计高程'],
          },
          xAxis: {
            type: 'category',
            boundaryGap: false,
            data: distanceArray,
          },
          yAxis: {
            type: 'value',
            axisLabel: {
              formatter: '{value} 米',
            },
            axisPointer: {
              snap: true,
            },
          },
          dataZoom: [
            {
              type: 'inside',
            },
            {
              start: 0,
              end: 10,
              handleIcon:
                'M10.7,11.9v-1.3H9.3v1.3c-4.9,0.3-8.8,4.4-8.8,9.4c0,5,3.9,9.1,8.8,9.4v1.3h1.3v-1.3c4.9-0.3,8.8-4.4,8.8-9.4C19.5,16.3,15.6,12.2,10.7,11.9z M13.3,24.4H6.7V23h6.6V24.4z M13.3,19.6H6.7v-1.4h6.6V19.6z',
              handleSize: '80%',
              handleStyle: {
                color: '#fff',
                shadowBlur: 3,
                shadowColor: 'rgba(0, 0, 0, 0.6)',
                shadowOffsetX: 2,
                shadowOffsetY: 2,
              },
            },
          ],
          // visualMap: {
          //     show: false,
          //     dimension: 0,
          //     pieces: [{ "gt": 0, "lte": 635 }]
          // },
          series: [
            {
              name: '地形高程',
              type: 'line',
              smooth: true,
              itemStyle: {
                normal: {
                  color: 'rgb(255, 255, 0)',
                },
              },
              data: heightTDArray,
            },
            {
              name: '设计高程',
              type: 'line',
              smooth: true,
              itemStyle: {
                normal: {
                  color: 'rgb(255, 70, 131)',
                },
              },
              data: heightArray,
              markPoint: undefined,
            },
          ],
        }
        myChart.setOption(option, true)

        // myChart.on('click', function (param) {
        //     map.trackedEntity = undefined;
        //     map.camera.flyTo({
        //         destination: Cesium.Cartesian3.fromDegrees(points[param.dataIndex][0], points[param.dataIndex][1], height + 30)
        //     });
        // });
      }

      function updateEchartsDistance(loc, height) {
        if (!myChart) {
          return
        }

        var markPoint = {
          data: [
            {
              name: '车',
              value: '车',
              xAxis: loc + 5,
              yAxis: height,
            },
          ],
        }

        // 填入数据,根据名字对应到相应的系列
        myChart.setOption({
          series: [
            {
              name: '设计高程',
              markPoint: markPoint,
            },
          ],
        })
      }
    </script>
  </body>
</html>
